package solver

func candsForHidden(candCounts [9]int, hiddenCount int) []int {
	cands := []int{}
	for cand, candCount := range candCounts {
		if candCount == 0 || candCount > hiddenCount {
			continue
		}
		cands = append(cands, cand)
	}
	return cands
}

func verifyHidden(cands []int, candCells [9][9]bool) (hidden bool, cellNums []int) {
	cells := [9]bool{}
	for _, cand := range cands {
		for i, cell := range candCells[cand] {
			cells[i] = cells[i] || cell
		}
	}

	cellCount := 0
	for _, cell := range cells {
		if cell {
			cellCount++
		}
	}
	hidden = cellCount == len(cands)

	if !hidden {
		return
	}
	for cellNum, cell := range cells {
		if cell {
			cellNums = append(cellNums, cellNum)
		}
	}
	return
}

func clearupHiddenHouse(house House, cellNums []int, cands []int) (used bool) {
	for _, cellNum := range cellNums {
		cell := house.cells[cellNum]
		if cell.removeCandidateBut(cands) {
			used = true
		}
	}
	return
}

func hiddenHouse(house House, hiddenCount int) (used bool) {
	candCells, candCounts := sumupCandCells(house)
	cands := candsForHidden(candCounts, hiddenCount)
	subsets := combine(cands, hiddenCount)
	for _, subset := range subsets {
		hidden, cellNums := verifyHidden(subset, candCells)
		if !hidden {
			continue
		}
		if clearupHiddenHouse(house, cellNums, subset) {
			logForNakedHidden("Hidden", house, cellNums, cands)
			used = true
		}
	}
	return
}

func (g *Grid) HiddenPairHouse(house House) (used bool) {
	return hiddenHouse(house, 2)
}

func (g *Grid) HiddenPair() (used bool) {
	return g.doStrategy(g.HiddenPairHouse)
}

func (g *Grid) HiddenTripleHouse(house House) (used bool) {
	return hiddenHouse(house, 3)
}

func (g *Grid) HiddenTriple() (used bool) {
	return g.doStrategy(g.HiddenTripleHouse)
}

func (g *Grid) HiddenQuandrupleHouse(house House) (used bool) {
	return hiddenHouse(house, 4)
}

func (g *Grid) HiddenQuandruple() (used bool) {
	return g.doStrategy(g.HiddenQuandrupleHouse)
}
